/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <gtest/gtest.h>
#include <mc/common.h>
#include <mc/memory.h>
#include <smbus/smbus.h>

namespace {

// Test fixture
class smbus_test : public ::testing::Test {
protected:
    void SetUp() override {
        m_smbus = mc::make_shared<dev::smbus>(nullptr);
    }

    void TearDown() override {
        m_smbus.reset();
    }

    mc::shared_ptr<dev::smbus> m_smbus;
};

// ========== 构造函数和析构函数测试 ==========

TEST_F(smbus_test, Constructor) {
    // 目标：验证 smbus 可以正常构造
    dev::smbus smbus_obj(nullptr);
    EXPECT_TRUE(true);
}

TEST_F(smbus_test, Destructor) {
    // 目标：验证 smbus 可以正常析构
    {
        dev::smbus smbus_obj(nullptr);
    }
    EXPECT_TRUE(true);
}

// ========== init 方法测试 ==========

TEST_F(smbus_test, init_Success) {
    // 目标：验证 init 方法可以正常初始化
    mc::mutable_dict params;
    params["BufferLen"] = static_cast<uint32_t>(64);
    params["McuAddress"] = static_cast<uint32_t>(0xD4);

    m_smbus->init(params);
    EXPECT_TRUE(true);
}

TEST_F(smbus_test, init_DifferentValues) {
    // 目标：验证 init 方法可以处理不同的值
    mc::mutable_dict params1;
    params1["BufferLen"] = static_cast<uint32_t>(128);
    params1["McuAddress"] = static_cast<uint32_t>(0xAA);

    m_smbus->init(params1);
    EXPECT_TRUE(true);

    mc::mutable_dict params2;
    params2["BufferLen"] = static_cast<uint32_t>(256);
    params2["McuAddress"] = static_cast<uint32_t>(0xBB);

    m_smbus->init(params2);
    EXPECT_TRUE(true);
}

// ========== register_WriteRead_method 方法测试 ==========

TEST_F(smbus_test, register_WriteRead_method) {
    // 目标：验证 register_WriteRead_method 方法可以注册函数
    bool called = false;
    std::function<std::vector<uint8_t>(const std::vector<uint8_t>&, uint32_t)> func =
        [&called](const std::vector<uint8_t>&, uint32_t) -> std::vector<uint8_t> {
        called = true;
        return std::vector<uint8_t>{0x01, 0x02};
    };

    m_smbus->register_WriteRead_method(func);
    EXPECT_TRUE(true);
}

// ========== get_max_frame_len 方法测试 ==========

TEST_F(smbus_test, get_max_frame_len) {
    // 目标：验证 get_max_frame_len 方法返回正确的值
    uint32_t max_frame_len = m_smbus->get_max_frame_len();
    // get_max_frame_len 返回 std_smbus::get_max_frame_len() - crc32_len
    // 由于 std_smbus 的默认实现，这里主要验证方法可以调用
    EXPECT_GE(max_frame_len, 0);
}

// ========== send_and_receive 方法测试 ==========

TEST_F(smbus_test, send_and_receive_WithoutRegisteredFunction) {
    // 目标：验证 send_and_receive 方法在未注册函数时返回 false
    std::string data = "test_data";
    uint32_t    len  = data.length();

    auto result = m_smbus->send_and_receive(data, len);
    EXPECT_FALSE(result.first);
    EXPECT_TRUE(result.second.empty());
}

TEST_F(smbus_test, send_and_receive_WithRegisteredFunction) {
    // 目标：验证 send_and_receive 方法在注册函数后可以正常工作
    std::vector<uint8_t> response_data = {0x01, 0x02, 0x03};
    std::function<std::vector<uint8_t>(const std::vector<uint8_t>&, uint32_t)> func =
        [response_data](const std::vector<uint8_t>&, uint32_t) -> std::vector<uint8_t> {
        return response_data;
    };

    m_smbus->register_WriteRead_method(func);

    std::string data = "test_data";
    uint32_t    len  = data.length();

    auto result = m_smbus->send_and_receive(data, len);
    EXPECT_TRUE(result.first);
    EXPECT_EQ(result.second, response_data);
}

TEST_F(smbus_test, send_and_receive_ExceptionHandling) {
    // 目标：验证 send_and_receive 方法在异常时返回 false
    std::function<std::vector<uint8_t>(const std::vector<uint8_t>&, uint32_t)> func =
        [](const std::vector<uint8_t>&, uint32_t) -> std::vector<uint8_t> {
        throw std::runtime_error("Test exception");
    };

    m_smbus->register_WriteRead_method(func);

    std::string data = "test_data";
    uint32_t    len  = data.length();

    auto result = m_smbus->send_and_receive(data, len);
    EXPECT_FALSE(result.first);
    EXPECT_TRUE(result.second.empty());
}

// ========== pack_smbus_request 方法测试 ==========

TEST_F(smbus_test, pack_smbus_request_Success) {
    // 目标：验证 pack_smbus_request 方法可以正确打包请求
    mc::mutable_dict request = {{"reserved", 0}, {"opcode", 0x0404}, {"offset", 0x56789ABC}, {"length", 0}};
    std::string result = m_smbus->pack_smbus_request(request);
    EXPECT_FALSE(result.empty());
    EXPECT_EQ(result.length(), sizeof(smbus_request_t));
}

TEST_F(smbus_test, pack_smbus_request_DifferentValues) {
    // 目标：验证 pack_smbus_request 方法可以处理不同的值
    mc::mutable_dict request = {{"reserved", 0x1234}, {"opcode", 0x5678}, {"offset", 0x9ABCDEF0}, {"length", 0x12345678}};
    std::string result = m_smbus->pack_smbus_request(request);
    EXPECT_FALSE(result.empty());
    EXPECT_EQ(result.length(), sizeof(smbus_request_t));
}

// ========== construct_request_data 方法测试 ==========

TEST_F(smbus_test, construct_request_data_Success) {
    // 目标：验证 construct_request_data 方法可以正确构造请求数据
    mc::mutable_dict track_request = {{"opcode", 0x0404}, {"data_written", 0}, {"len", 10}};
    std::string result = m_smbus->construct_request_data(track_request);
    EXPECT_FALSE(result.empty());
    // 结果应该包含请求数据和 CRC32
    EXPECT_GT(result.length(), sizeof(smbus_request_t));
}

// ========== unpack_response_data 方法测试 ==========

TEST_F(smbus_test, unpack_response_data_Success) {
    // 目标：验证 unpack_response_data 方法可以正确解包响应数据
    // 构造一个有效的响应数据（包含 header + data + crc32）
    std::string rsp_bin;
    
    // error_code (2 bytes)
    uint16_t error_code = 0;
    rsp_bin.append(reinterpret_cast<const char*>(&error_code), sizeof(error_code));
    
    // opcode (2 bytes)
    uint16_t opcode = 0x0404;
    rsp_bin.append(reinterpret_cast<const char*>(&opcode), sizeof(opcode));
    
    // total_length (4 bytes)
    uint32_t total_length = 20;
    rsp_bin.append(reinterpret_cast<const char*>(&total_length), sizeof(total_length));
    
    // length (4 bytes)
    uint32_t length = 4;
    rsp_bin.append(reinterpret_cast<const char*>(&length), sizeof(length));
    
    // data (4 bytes)
    std::string data = "test";
    rsp_bin.append(data);
    
    // 计算 CRC32
    std::string bin_data = rsp_bin;
    auto crc_cal = mc::crypto::CRC32().calculate(bin_data, 0, true);
    rsp_bin.append(reinterpret_cast<const char*>(&crc_cal), sizeof(crc_cal));

    // 初始化 smbus
    mc::mutable_dict params;
    params["BufferLen"]   = static_cast<uint32_t>(64);
    params["McuAddress"] = static_cast<uint32_t>(0xD4);
    m_smbus->init(params);

    auto result = m_smbus->unpack_response_data(rsp_bin, 4);
    EXPECT_TRUE(result.first);
    EXPECT_EQ(result.second["opcode"].as<uint16_t>(), opcode);
    EXPECT_EQ(result.second["length"].as<uint32_t>(), length);
}

TEST_F(smbus_test, unpack_response_data_CRCError) {
    // 目标：验证 unpack_response_data 方法在 CRC 错误时返回 false
    std::string rsp_bin;
    
    // 构造一个 CRC 错误的响应数据
    uint16_t error_code = 0;
    rsp_bin.append(reinterpret_cast<const char*>(&error_code), sizeof(error_code));
    
    uint16_t opcode = 0x0404;
    rsp_bin.append(reinterpret_cast<const char*>(&opcode), sizeof(opcode));
    
    uint32_t total_length = 20;
    rsp_bin.append(reinterpret_cast<const char*>(&total_length), sizeof(total_length));
    
    uint32_t length = 4;
    rsp_bin.append(reinterpret_cast<const char*>(&length), sizeof(length));
    
    std::string data = "test";
    rsp_bin.append(data);
    
    // 使用错误的 CRC32
    uint32_t wrong_crc = 0x12345678;
    rsp_bin.append(reinterpret_cast<const char*>(&wrong_crc), sizeof(wrong_crc));

    // 初始化 smbus
    mc::mutable_dict params;
    params["BufferLen"]   = static_cast<uint32_t>(64);
    params["McuAddress"] = static_cast<uint32_t>(0xD4);
    m_smbus->init(params);

    auto result = m_smbus->unpack_response_data(rsp_bin, 4);
    EXPECT_FALSE(result.first);
    EXPECT_TRUE(result.second.contains("error_msg"));
}

// ========== send_and_receive_request_in_frames 方法测试 ==========

TEST_F(smbus_test, send_and_receive_request_in_frames_EmptyData) {
    // 目标：验证 send_and_receive_request_in_frames 方法可以处理空数据
    mc::mutable_dict track_request = {{"opcode", 0x0404}, {"data_written", 1}, {"data", "ssss"}, {"max_frame_len", 64}};
    // 由于未注册 WriteRead 函数，应该返回 false
    auto result = m_smbus->send_and_receive_request_in_frames(track_request);
    EXPECT_FALSE(result.first);
}

TEST_F(smbus_test, DISABLED_send_and_receive_request_in_frames_WithData) {
    // 目标：验证 send_and_receive_request_in_frames 方法可以处理有数据的情况
    std::vector<uint8_t> response_data = {0x01, 0x02};
    std::function<std::vector<uint8_t>(const std::vector<uint8_t>&, uint32_t)> func =
        [response_data](const std::vector<uint8_t>&, uint32_t) -> std::vector<uint8_t> {
        return response_data;
    };

    m_smbus->register_WriteRead_method(func);

    // 初始化 smbus
    mc::mutable_dict params = {{"BufferLen", 64}, {"McuAddress", 0xD4}};
    m_smbus->init(params);

    mc::mutable_dict track_request = {{"opcode", 0x0404}, {"data_written", 2}, {"data", "test_data_longer_than_max_frame"}, {"max_frame_len", 10}};
    auto result = m_smbus->send_and_receive_request_in_frames(track_request);
    // 由于需要构造请求数据并发送，结果取决于实现
    EXPECT_TRUE(true);
}

TEST_F(smbus_test, DISABLED_send_and_receive_request_in_frames_PartialData) {
    // 目标：验证 send_and_receive_request_in_frames 方法可以处理部分数据
    std::vector<uint8_t> response_data = {0x01, 0x02};
    std::function<std::vector<uint8_t>(const std::vector<uint8_t>&, uint32_t)> func =
        [response_data](const std::vector<uint8_t>&, uint32_t) -> std::vector<uint8_t> {
        return response_data;
    };

    m_smbus->register_WriteRead_method(func);

    // 初始化 smbus
    mc::mutable_dict params = {{"BufferLen", 64}, {"McuAddress", 0xD4}};
    m_smbus->init(params);

    mc::mutable_dict track_request = {{"opcode", 0x0404}, {"data_written", 1}, {"data", "test_data_longer_than_max_frame"}, {"max_frame_len", 10}};
    auto result = m_smbus->send_and_receive_request_in_frames(track_request);
    EXPECT_TRUE(true);
}

} // namespace

